package cn.isjinhao.se.sql.grammar.statement.delete;

import cn.isjinhao.se.sql.function.evaluator.FunctionEvaluator;
import cn.isjinhao.se.sql.grammar.CurdStatement;
import cn.isjinhao.se.sql.grammar.GrammarErrorReporterDelegate;
import cn.isjinhao.se.sql.grammar.statement.Grouping;
import cn.isjinhao.se.sql.grammar.statement.StatementParser;
import cn.isjinhao.se.sql.grammar.statement.delete.represention.Delete;
import cn.isjinhao.se.sql.grammar.statement.delete.visitor.SingleDeleteMetaInfoDetector;
import cn.isjinhao.se.sql.lexical.scan.TokenSequence;
import cn.isjinhao.se.sql.lexical.token.Token;
import cn.isjinhao.se.sql.lexical.token.TokenType;

/**
 * @Author ISJINHAO
 * @Date 2021/4/8 20:37
 */
public class DeleteParser extends StatementParser {

    public DeleteParser(TokenSequence tokenSequence, FunctionEvaluator functionEvaluator) {
        super(tokenSequence, functionEvaluator);
    }

    /**
     * delete           ->  "delete" "from" IDENTIFIER whereSeg
     *
     * whereSeg         ->  "where" logic
     *
     * logic            ->  condition (("or" | "and") condition)*
     * condition        ->  comparison
     * comparison       ->  binaryArithmetic ((">" | "<" | ">=" | "<=" | "!=" | "=" | "like" | "contains") binaryArithmetic)?
     * binaryArithmetic ->  unaryArithmetic (("+" | "-" | "*" | "/") unaryArithmetic)*
     * unaryArithmetic  ->  ("!"|"-") unaryArithmetic | primary
     *
     * primary          ->  #{xxx} | ? | "true" | "false" | "null" | NUMBER | STRING | IDENTIFIER | function | "(" logic ")"
     * function         ->  functionName "(" binaryArithmetic? ("," binaryArithmetic)* ")"
     * functionName     ->  "date_to_timestamp" | "date_to_str" | "str_to_date" | "str_to_timestamp" | "timestamp_to_date" | "timestamp_to_str" | "now"
     *
     */
    @Override
    public CurdStatement parse() {
        CurdStatement delete = delete();
        delete.accept(new SingleDeleteMetaInfoDetector());
        return delete;
    }

    private CurdStatement delete() {
        consume(TokenType.DELETE, GrammarErrorReporterDelegate.DELETE_delete_PARSE);
        consume(TokenType.FROM, GrammarErrorReporterDelegate.DELETE_delete_PARSE);

        Token tableName = tokenSequence.takeCur();
        if(!TokenType.IDENTIFIER.equals(tableName.getType())) {
            error(GrammarErrorReporterDelegate.DELETE_delete_PARSE);
        }
        tokenSequence.advance();

        CurdStatement whereSeg = whereSeg();

        return new Delete(tableName, whereSeg);
    }

    @Override
    protected CurdStatement primary() {
        CurdStatement primary = super.primary();
        if(primary != null) {
            return primary;
        }

        // "(" logic ")"
        else if (tokenSequence.equalThenAdvance(TokenType.LEFT_PAREN)) {
            CurdStatement curdStatement = logic();
            consume(TokenType.RIGHT_PAREN, GrammarErrorReporterDelegate.DELETE_primary_PARSE);
            return new Grouping(curdStatement);
        }

        error(GrammarErrorReporterDelegate.DELETE_primary_PARSE);
        return null;
    }

}
